home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…eptember: Technology Seed / September 98 ADC Seed CD.toast / FireWire 1.1 DR2 SDK / Source / OpenTransport / FWOTDriver / DLPIRoutines.c next >
Encoding:
Text File  |  1998-01-15  |  66.9 KB  |  2,154 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DLPIRoutines.c
  3.  
  4.     Contains:    This file contains the routine(s) to handle the DLPI calls from the
  5.                 client.  This file is very hardware independent.
  6.  
  7.     Written by:    
  8.  
  9.     Copyright:    © 1994, 1996 by Apple Computer, Inc., all rights reserved.
  10.  
  11.     Change History (most recent first):
  12.  
  13.        <FW2>      8/1/96    ES        Took out unused local variables.
  14.          <1>     3/27/96    ES        first checked in
  15.  
  16.     To Do:
  17. */
  18.  
  19. //-----------------------------------------------------------------------------------------
  20. //    Include files
  21. //-----------------------------------------------------------------------------------------
  22.  
  23. #include <OpenTptModule.h>            // Open Transport files
  24. #include <OpenTptDevLinks.h>
  25. #include <OpenTptLinks.h>
  26. #include <stropts.h>
  27. #include <dlpi.h>
  28.  
  29. #include <OSUtils.h>                // System files
  30. #include <Kernel.h>
  31. #include <DriverServices.h>
  32. #include <NameRegistry.h>
  33. #include <Interrupts.h>
  34.  
  35.  
  36. #include "EntryPoints.h"            // our files
  37. #include "DLPIRoutines.h"
  38. #include "HWSpecific.h"
  39. /*zzz*/
  40. static char  debugStr[256];
  41. /*zzz*/
  42.  
  43. //-----------------------------------------------------------------------------------------
  44. // Global variable for the entire CFM
  45. //-----------------------------------------------------------------------------------------
  46.  
  47. extern    DLPIPrivateData *gDLPIPrivateData;        // Declared in EntryPoints.c
  48.  
  49. //-----------------------------------------------------------------------------------------
  50. //    Description:
  51. //        A message block is passed to this routine, the routine determines if the message
  52. //        block can handled a certain size of data.  The reuse algorithm is done in this
  53. //        order:
  54. //    
  55. //            1. Reuse M_(PC)PROTO if available.
  56. //            2. Try to prepend header to first data block.
  57. //            3. Allocate a new message block to hold the header.
  58. //
  59. //    Input:
  60. //        mp - attempt to reuse the message block for a new message
  61. //        dataSizeNeeded - indicates the size of the new message needed
  62. //
  63. //    Output:
  64. //        message block pointer - to a newly allocate message block or the original mb
  65. //
  66. //-----------------------------------------------------------------------------------------
  67. mblk_t *ReuseMessageBlock(mblk_t *mp,UInt16 dataSizeNeeded)
  68. {
  69. mblk_t         *nmp;
  70.  
  71. if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim -  mp->b_datap->db_base) >= dataSizeNeeded)) 
  72.     {
  73.     mp->b_datap->db_type = M_DATA;
  74.     mp->b_rptr = mp->b_datap->db_base;
  75.     mp->b_wptr = mp->b_datap->db_base + dataSizeNeeded;
  76.     } 
  77. else 
  78.     {
  79.     nmp = mp->b_cont;                 // grab the M_DATA blocks
  80.     mp->b_cont = NULL;                 // detach the M_(PC)PROTO
  81.     freemsg(mp);                    // free the M_(PC)PROTO
  82.     mp = nmp;                        // point to the M_DATA blocks
  83.  
  84.         // try to get space on the first M_DATA block
  85.     if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= dataSizeNeeded)) 
  86.         mp->b_rptr -= dataSizeNeeded;
  87.     else 
  88.         {
  89.         if ((nmp = allocb(dataSizeNeeded, BPRI_HI)) == NULL)     // try to allocate a new message
  90.             {    // could not get a new message block so lets forget about the message altogether
  91.             freemsg(mp);             // free the original M_DATA portion of the message
  92.             mp = NULL;                 // indicates the reuse failed
  93.             }
  94.         else     
  95.             {
  96.             nmp->b_cont = mp;        // attach the new message block as the head
  97.             nmp->b_wptr += dataSizeNeeded;
  98.             mp = nmp;                 
  99.             } 
  100.         }
  101.     }
  102.  
  103. return mp;
  104. }
  105.  
  106. //-----------------------------------------------------------------------------------------
  107. //    Description:
  108. //        This routine builds a header for a packet that will be transmitted.  The passed
  109. //        in message (mp) has the header info in the first message block and then
  110. //        data in the following message blocks.  This routine uses the destination address
  111. //        info in the first message block to construct an Ethernet header which includes
  112. //        the dest, source (0, till sending packet), protocol/length (depends on the type
  113. //        of packet), and possible 802.2 sap and snap.  This header
  114. //        will contain the source, destination, type/length, and SAP/SNAP components.  The
  115. //        header that is built can be used for a packet header or a fast path header.
  116. //
  117. //    Input:
  118. //        theStream - the stream originating the packet
  119. //        mp - message block that contains info (source)
  120. //        forFastPathOnly - this flag determines if this is for the Mentat fastpath or
  121. //            a real packet header
  122. //
  123. //    Output:
  124. //        returns a message block that contains a formed packet header
  125. //
  126. //-----------------------------------------------------------------------------------------
  127. mblk_t *BuildTxPacketHeader(DLPIStream *theStream, mblk_t *mp, Boolean forFastPathOnly)
  128. {
  129.  
  130. UInt16                             hdrsize, datasize, dlsap;
  131. struct T8022FullPacketHeader     *packetHeader;
  132. UInt8                             *snapStart;
  133. UInt16                             proto,packetType;
  134. UInt8                             ctrl, responseFlag = 0;
  135. UInt8                             destAddrCopy[kMaxBoundAddrLength], *destAddrOrig, *reqStart;
  136. UInt32                            destAddrLen;
  137.  
  138. reqStart = mp->b_rptr;
  139.  
  140. switch (((union DL_primitives *)(reqStart))->dl_primitive)
  141.     {
  142.     case DL_UNITDATA_REQ:
  143.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_offset;
  144.         destAddrLen = ((dl_unitdata_req_t*)reqStart)->dl_dest_addr_length;
  145.         ctrl = 0x03;
  146.         break;
  147.         
  148.     case DL_TEST_REQ:
  149.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_test_req_t*)reqStart)->dl_dest_addr_offset;
  150.         destAddrLen = ((dl_test_req_t*)reqStart)->dl_dest_addr_length;
  151.         ctrl = (((dl_test_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
  152.         break;
  153.         
  154.     case DL_XID_REQ:
  155.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_xid_req_t*)reqStart)->dl_dest_addr_offset;
  156.         destAddrLen = ((dl_xid_req_t*)reqStart)->dl_dest_addr_length;
  157.         ctrl = (((dl_xid_req_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
  158.         break;
  159.         
  160.     case DL_TEST_RES:
  161.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_test_res_t*)reqStart)->dl_dest_addr_offset;
  162.         destAddrLen = ((dl_test_res_t*)reqStart)->dl_dest_addr_length;
  163.         ctrl = (((dl_test_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xF3 : 0xE3;
  164.         responseFlag = 1;
  165.         break;
  166.         
  167.     case DL_XID_RES:
  168.         destAddrOrig = ((UInt8*)reqStart) +  ((dl_xid_res_t*)reqStart)->dl_dest_addr_offset;
  169.         destAddrLen = ((dl_xid_res_t*)reqStart)->dl_dest_addr_length;
  170.         ctrl = (((dl_xid_res_t*)reqStart)->dl_flag & DL_POLL_FINAL) ? 0xBF : 0xAF;
  171.         responseFlag = 1;
  172.         break;
  173.     default:
  174.         freemsg(mp);
  175.         return NULL;
  176.         break;
  177.     }
  178.  
  179. switch(destAddrLen)
  180.     {
  181.     case kEnetPhysicalAddressLength:    
  182.         dlsap = theStream->dlsap;
  183.         break;
  184.     case kEnetAndSAPAddressLength:    
  185.         dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
  186.         break;
  187.     case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength:    // snap sap
  188.         dlsap = *(UInt16 *)(destAddrOrig + kEnetPhysicalAddressLength);
  189.         break;
  190.     default:
  191.         dlsap = theStream->dlsap;
  192.         break;
  193.     }
  194.     
  195. datasize = msgdsize(mp);    // this does not include header info    
  196.     
  197. packetType = ClassifyPacketType(theStream->dlsap,dlsap);
  198.  
  199. switch(packetType)
  200.     {
  201.     case kPktDIX:
  202.         hdrsize = kEnetPacketHeaderLength; 
  203.         proto = dlsap;
  204.         break;
  205.     case kPkt8022SAP:
  206.         hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  207.         if (forFastPathOnly)
  208.             proto = 0;
  209.         else
  210.             proto = (datasize + k8022BasicHeaderLength);
  211.         break;
  212.     case kPkt8022SNAP:
  213.         hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
  214.         if (forFastPathOnly)
  215.             proto = 0;        
  216.         else
  217.             proto = datasize + k8022SNAPHeaderLength;
  218.         break;
  219.     case kPktIPX:
  220.         hdrsize = kEnetPacketHeaderLength;
  221.         if (forFastPathOnly)
  222.             proto = 0;
  223.         else
  224.             proto = datasize;        
  225.         break;
  226.     default:
  227.         hdrsize = kEnetPacketHeaderLength; 
  228.         proto = dlsap;
  229.         break;
  230.     }
  231.     
  232.     // we need to copy the dest address info in the message before we can reuse it
  233. bcopy(destAddrOrig, destAddrCopy, destAddrLen);
  234.     
  235. if ((mp = ReuseMessageBlock(mp,hdrsize)) == NULL)
  236.     return NULL;
  237.  
  238. packetHeader = (struct T8022FullPacketHeader *)mp->b_rptr;
  239.  
  240. packetHeader->fEnetPart.fProto = proto;        // set proto or length
  241.  
  242. switch(packetType)
  243.     {
  244.     case kPkt8022SAP:
  245.         packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
  246.         packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
  247.         packetHeader->f8022Part.fCtrl = ctrl;
  248.         break;
  249.     case kPkt8022SNAP:
  250.         packetHeader->f8022Part.fDSAP = (UInt8 )dlsap;
  251.         packetHeader->f8022Part.fSSAP = ((UInt8 )theStream->dlsap) | responseFlag;
  252.         packetHeader->f8022Part.fCtrl = ctrl;
  253.         if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength)
  254.             snapStart = destAddrCopy + kEnetAndSAPAddressLength;
  255.         else
  256.             snapStart = theStream->snap;
  257.         OTCopy8022SNAP(snapStart,packetHeader->f8022Part.fSNAP);
  258.         break;
  259.     default:
  260.         break;
  261.     }
  262.  
  263. OTCopy48BitAddress(destAddrCopy,packetHeader->fEnetPart.fDestAddr);
  264.  
  265. return(mp);
  266. }
  267.  
  268. //-----------------------------------------------------------------------------------------
  269. //    Description:
  270. //        This routine checks if the address is a multicast address, broadcast, or standard
  271. //        address.
  272. //
  273. //    Input:
  274. //        addr - pointer to an array of 6 bytes that is an ethernet address 
  275. //
  276. //    Output:
  277. //        return type of address
  278. //
  279. //-----------------------------------------------------------------------------------------
  280. SInt32 GetAddressType(UInt8 *addr) 
  281. {
  282.  
  283. if (addr[0] & 1)     // is address multicast or broadcast
  284.     {
  285.     if (OTIs48BitBroadcastAddress(addr))
  286.         return keaBroadcast;
  287.     else
  288.         return keaMulticast;
  289.     } 
  290. else
  291.     return keaStandardAddress;
  292. }
  293.  
  294. //-----------------------------------------------------------------------------------------
  295. //    Description:
  296. //        This routine handles the binding of a stream.  The stream must not be in the 
  297. //        bind state when this call is made.  In other words, a stream can only be bound
  298. //        once.  The call is ack'd by doing sending a message block with a bind ack
  299. //        message.
  300. //
  301. //    Input:
  302. //        theStream - the stream that the client wants to bind
  303. //        mp - message block that contains the parameters for the bind call
  304. //
  305. //    Output:
  306. //        returns the status of the call
  307. //
  308. //-----------------------------------------------------------------------------------------
  309. SInt32 BindTheStream(DLPIStream *theStream, mblk_t *mp)
  310. {
  311. dl_bind_req_t     *req = (dl_bind_req_t *)mp->b_rptr;
  312. UInt16             dlsap = (UInt16)req->dl_sap;
  313. mblk_t             *ack_mp;
  314. SInt32             i;
  315.  
  316. if (req->dl_service_mode != DL_CLDLS) 
  317.     return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0));
  318.  
  319. if (theStream->dlpiState != DL_UNBOUND) 
  320.     return(DoErrorAck(theStream, mp, DL_BIND_REQ, DL_OUTSTATE, 0));
  321.  
  322.     // don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF)
  323.     //  because it looks like IPX
  324. if ((dlsap < kMax8022SAP) && (dlsap & 1))    
  325.     return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
  326.  
  327. if (ClassifyPacketType(dlsap,dlsap) == kPktUnknown)
  328.     return (DoErrorAck(theStream, mp, DL_BIND_REQ, DL_BADADDR, 0));
  329.  
  330. if ((ack_mp = BuildBindAck(theStream, dlsap)) == NULL)
  331.     return (kdlpiRETRY);
  332.  
  333. for (i = 0; i < kGroupSAPMapSize; i++)
  334.     theStream->group_sap[i] = 0;
  335.     
  336. if (dlsap <= kMax8022SAP)
  337.     SetGroupSAP(theStream, k8022GlobalSAP);    
  338.  
  339. if (req->dl_xidtest_flg & DL_AUTO_XID)
  340.     theStream->streamFlags |= kAutoXID;    
  341.  
  342. if (req->dl_xidtest_flg & DL_AUTO_TEST)
  343.     theStream->streamFlags |= kAutoTest;    
  344.  
  345. freemsg(mp);
  346.  
  347. theStream->dlpiState = DL_IDLE;
  348. theStream->dlsap = dlsap;
  349. theStream->streamFlags &= ~kSnapStream;
  350. putnext(theStream->readQueue, ack_mp);     // and reply with the ACK
  351. return (kdlpiDONE);
  352. }
  353.  
  354. //-----------------------------------------------------------------------------------------
  355. //    Description:
  356. //        This routine builds the bind ack message block.
  357. //
  358. //    Input:
  359. //        theStream - the stream to send the bind ack to
  360. //        dlsap - the sap for the current stream
  361. //
  362. //    Output:
  363. //        returns a message block that contains the bind ack message
  364. //
  365. //-----------------------------------------------------------------------------------------
  366. mblk_t *BuildBindAck(DLPIStream *theStream, UInt16 dlsap)
  367. {
  368. dl_bind_ack_t    *ackp;
  369. mblk_t             *mp;
  370. T8022AddressStruct    *addrInfo;
  371.  
  372. if ((mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) 
  373.     {
  374.     DoWriteScheduler(theStream, sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength);
  375.     return(NULL);
  376.     }
  377.     
  378. mp->b_datap->db_type = M_PCPROTO;
  379. ackp = (dl_bind_ack_t *)mp->b_rptr;
  380. ackp->dl_primitive = DL_BIND_ACK;
  381. ackp->dl_sap = dlsap;
  382. ackp->dl_addr_length = kEnetAndSAPAddressLength;        
  383. ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
  384. ackp->dl_max_conind = 0;
  385. ackp->dl_xidtest_flg = 0;
  386.  
  387. addrInfo = (T8022AddressStruct *)(mp->b_rptr + sizeof(dl_bind_ack_t));
  388. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,addrInfo->fHWAddr);
  389. addrInfo->fSAP = dlsap;
  390.  
  391.     // must move b_wptr past the address info data
  392. mp->b_wptr = mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength;
  393.     
  394. return(mp);
  395. }
  396.  
  397.  
  398. //-----------------------------------------------------------------------------------------
  399. //    Description:
  400. //         This routine builds a header from a packet that was received.  The header
  401. //        includes the destination and source address.  The sap and snap are also
  402. //        copied.
  403. //
  404. //                        Ethernet Header
  405. //                    +-----------------------+
  406. //      packetHeader    |      dest addr        |    6 bytes
  407. //                    +-----------------------+
  408. //                    |      src addr         |    6 bytes
  409. //                    +-----------------------+
  410. //                    |      type/protocol    |    2 bytes
  411. //                    +-----------------------+
  412. //                    |      dest SAP         |    1 bytes        802.2 and IPX only
  413. //                    +-----------------------+
  414. //                    |      src SAP          |    1 bytes        802.2 and IPX only
  415. //                    +-----------------------+
  416. //                    |      control          |    1 bytes        802.2 only
  417. //                    +-----------------------+
  418. //                    |      SNAP             |    5 bytes        802.2 and 0xAA dest sap
  419. //                    +-----------------------+
  420. //
  421. //        The Ethernet header information must be moved into a memory block with
  422. //        the following format:
  423. //
  424. //                        Indication Header
  425. //                    +-----------------------+
  426. //        destAddr    |      dest addr        |    6 - 13 bytes 
  427. //                    +-----------------------+
  428. //        srcAddr        |      src addr         |    6 - 13 bytes
  429. //                    +-----------------------+
  430. //    
  431. //        The Indication header destination and source address fields can contain from
  432. //        6 to 13 bytes.  The minimum is the Ethernet addresses from the Ethernet header.
  433. //        They could also contain the sap and snap information:
  434. //
  435. //                    dest or src addr format
  436. //                    +-----------------------+
  437. //                    |     Ethernet addr     |    6 bytes 
  438. //                    +-----------------------+
  439. //                    |         SAP             |    2 bytes
  440. //                    +-----------------------+
  441. //                    |         SNAP             |    5 bytes
  442. //                    +-----------------------+
  443. //
  444. //    Input:
  445. //        mp - message block that contains the info for building a test message
  446. //        dlsap_length - the number of bytes in the mp message block 
  447. //
  448. //    Output:
  449. //        returns a message block that contains an the test message
  450. //
  451. //-----------------------------------------------------------------------------------------
  452. void BuildRxDestSrcHeader(T8022FullPacketHeader *packetHeader,
  453.                             T8022AddressStruct *destAddr,
  454.                             T8022AddressStruct *srcAddr,
  455.                             UInt32 dlsap_length)
  456.                             
  457. {
  458.  
  459. OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr,destAddr->fHWAddr);
  460. OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr,srcAddr->fHWAddr);
  461.  
  462.     //    Pull 8022 SAP from packet, if bytes remain in the dlsap_length.
  463.  
  464. switch (dlsap_length) 
  465.     {
  466.     case kEnetAndSAPAddressLength + k8022SNAPLength:
  467.         OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,destAddr->fSNAP);
  468.         OTCopy8022SNAP(packetHeader->f8022Part.fSNAP,srcAddr->fSNAP);
  469.                                         // no break because we want to do the sap also
  470.     case kEnetAndSAPAddressLength:
  471.         destAddr->fSAP = packetHeader->f8022Part.fDSAP;
  472.         srcAddr->fSAP = packetHeader->f8022Part.fSSAP;
  473.         break;
  474.         
  475.     default:        // for Ethernet address do nothing
  476.         break;
  477.     }
  478.     
  479. }
  480.  
  481. //-----------------------------------------------------------------------------------------
  482. //    Description:
  483. //        This routines builds the message block for the Indication message. The appropriate
  484. //        information is set in the message.  The destination and source dlsaps are put
  485. //        into the M_PROTO block.  These dlsaps could be classic ethernet, 802.2, or IPX.
  486. //        The "data" portion of the message only contains pure data.  For 802.2 this
  487. //        is everything past the snap or sap if there is no snap.  For classic ethernet
  488. //        this is everything past the protocol type.  For IPX this includes FF FF 03 +
  489. //        the data.
  490. //
  491. //    Input:
  492. //        mp - message block that contains the info for building a indication message
  493. //        dlsap_length - the number of bytes in the mp message block 
  494. //
  495. //    Output:
  496. //        returns a message block that contains an the Indication message
  497. //
  498. //-----------------------------------------------------------------------------------------
  499. void BuildUnitDataIndication(DLPIStream *theStream, mblk_t *mp, 
  500.         UInt16 destAddrLength, UInt16 headerHideLength)
  501. {
  502. mblk_t                 *nmp;
  503. dl_unitdata_ind_t     *ind;
  504. SInt32                     addressType;
  505. T8022FullPacketHeader    *packetHeader;
  506. T8022AddressStruct        *srcAddr,*destAddr;
  507.  
  508.     //    Allocate the dl_unitdata_ind_t message, and fill it in.
  509. if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + (2 * destAddrLength), BPRI_HI)) == NULL)
  510.     {
  511.     freemsg(mp);
  512.     return;
  513.     }
  514.  
  515. nmp->b_datap->db_type = M_PROTO;
  516.     
  517. ind = (dl_unitdata_ind_t*)nmp->b_rptr;
  518. ind->dl_primitive = DL_UNITDATA_IND;
  519. ind->dl_dest_addr_length = destAddrLength;
  520. ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
  521. ind->dl_src_addr_length = destAddrLength;
  522. ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + destAddrLength;
  523.  
  524. addressType = GetAddressType(mp->b_rptr);
  525. if (addressType == keaStandardAddress)
  526.     ind->dl_group_address = 0;
  527. else
  528.     ind->dl_group_address = addressType;    // broadcast or multicast
  529.  
  530. nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + destAddrLength + destAddrLength);
  531.  
  532. packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
  533.  
  534. destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
  535. srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
  536.  
  537. BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
  538.  
  539. if (theStream->streamFlags & kReadRawPackets)    // a raw packet comming in
  540.     ind->dl_group_address |= keaRawPacketBit;    // marks packet as raw
  541. else
  542.     mp->b_rptr += headerHideLength;    // "hide" the ethernet and protocol header(s)
  543.     
  544. linkb(nmp, mp);        // append dlpi header to the packet data message block.
  545. putnext(theStream->readQueue, nmp);        // pass the message up the stream
  546. return;
  547.  
  548. }
  549.  
  550. //-----------------------------------------------------------------------------------------
  551. //    Description:
  552. //        Process M_DATA mblk_ts from the device (the lower half of the driver.
  553. //        This is the basic client stream service routine to prepend the right kind 
  554. //        of DLPI information to the raw data coming in off the wire.  The packet is
  555. //         then placed on the stream read queue for processing by our client.
  556. //
  557. //    Input:
  558. //        theStream - the stream that will receive this packet
  559. //        mp - the message block that contains the received packet
  560. //
  561. //    Output:
  562. //        no return value explicitly
  563. //
  564. //-----------------------------------------------------------------------------------------
  565. void HandleReceivedPacket(DLPIStream *theStream, mblk_t *mp, UInt16 packetType)
  566. {
  567. Boolean        isTest = kFalse;
  568. Boolean        isXID = kFalse;
  569. Boolean        isCommand = kTrue;
  570. UInt16        destAddrLength;
  571. UInt32        headerHideLength;
  572. UInt8        ctrl;
  573. Boolean        is8022 = kFalse;
  574.  
  575. switch( packetType )
  576.     {
  577.     case kPktDIX:
  578.         destAddrLength = kEnetPhysicalAddressLength;
  579.         headerHideLength = kEnetPacketHeaderLength;
  580.         break;
  581.     case kPkt8022SAP:
  582.         destAddrLength = kEnetAndSAPAddressLength;
  583.         headerHideLength = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  584.         is8022 = kTrue;
  585.         break;
  586.     case kPkt8022SNAP:
  587.         destAddrLength = kEnetAndSAPAddressLength + k8022SNAPLength;
  588.         headerHideLength = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
  589.         is8022 = kTrue;
  590.         break;
  591.     case kPktIPX:
  592.         destAddrLength = kEnetPhysicalAddressLength;
  593.         headerHideLength = kEnetPacketHeaderLength;
  594.         break;
  595.     default:
  596.         break;
  597.     }
  598.  
  599. if (theStream->streamFlags & kReadRawPackets)    // raw packet comming in
  600.     {
  601.     BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
  602.     return;
  603.     }
  604.  
  605.  
  606. if (is8022)
  607.     {
  608.     ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
  609.     isTest = (ctrl & 0xEF) == 0xE3;
  610.     isXID = (ctrl & 0xEF) == 0xAF;
  611.     isCommand = (((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP & 1) == 0;
  612.  
  613.     if (isTest && isCommand && (theStream->streamFlags & kAutoTest)) 
  614.         {
  615.         DoTestResponse(theStream, mp);
  616.         return;
  617.         }
  618.  
  619.     if (isXID && isCommand && (theStream->streamFlags & kAutoXID)) 
  620.         {
  621.         DoXidResponse(theStream, mp);
  622.         return;
  623.         }
  624.     
  625.     if (isTest || isXID)    // indication (request) or confirmation (response, auto off)
  626.         {
  627.         BuildXidTestConfirmIndication(theStream, mp, destAddrLength, headerHideLength);
  628.         return;
  629.         }
  630.  
  631.     }
  632.  
  633.     // send packet up the stream
  634. BuildUnitDataIndication(theStream, mp, destAddrLength, headerHideLength);
  635.  
  636. }
  637.  
  638. //-----------------------------------------------------------------------------------------
  639. //    Description:
  640. //        This routine is called because the callee wants to check if the passed in
  641. //        multicast ethernet address has already been registered with this stream.  A linked
  642. //        list of message blocks that contain 1 registered multicast address is kept on
  643. //        a per stream basis.  This routine call also be used to dequeue the mb that
  644. //        contains the already registered multicast address.
  645. //
  646. //    Input:
  647. //        multicastQueue - pointer to a queue header for the linked list of mb's
  648. //        reqaddr - ethernet multicast address to be checked against the linked list
  649. //        dequeueBlock - determines whether the mb containing the registered multicast 
  650. //            should be dequeued from the linked list
  651. //
  652. //    Output:
  653. //        returns null if no match is found, returns the mb if it is found
  654. //
  655. //-----------------------------------------------------------------------------------------
  656. mblk_t *IsAddressRegistered(QHdr *multicastQueue,UInt8 *reqaddr, Boolean dequeueBlock,
  657.     UInt16 interruptMask)
  658. {
  659. mblk_t    *mbWalker;
  660.  
  661.  
  662. ABCVendorDisableInterrupts(interruptMask);        
  663.  
  664. if ((mbWalker = (mblk_t *)multicastQueue->qHead) == NULL)
  665.     {
  666.     ABCVendorEnableInterrupts(interruptMask);
  667.     return NULL;
  668.     }
  669.  
  670. while (mbWalker) 
  671.     {
  672.     if (CheckAddressMatch((UInt8 *)mbWalker->b_rptr, reqaddr, kEnetPhysicalAddressLength)) 
  673.         {
  674.         if (dequeueBlock)
  675.             DequeueElement(multicastQueue,(QElem *)mbWalker, 0);
  676.         break;
  677.         }
  678.     else
  679.         mbWalker = mbWalker->b_next;    // check the next mb/address
  680.     }
  681.     
  682. ABCVendorEnableInterrupts(interruptMask);
  683.  
  684.  
  685. return mbWalker;
  686.  
  687. }
  688.  
  689. //-----------------------------------------------------------------------------------------
  690. //    Description:
  691. //        This routine handles removing a registered multicast address from the stream.
  692. //        First the address is checked to make sure it is a valid multicast address.
  693. //        Then the mc is checked to see if it has actually been registered.  If
  694. //        everything passes then an OK ack is sent to the client.  If not then an error
  695. //        ack is sent.
  696. //
  697. //    Input:
  698. //        theStream - the stream requesting the disable
  699. //        mp - message block containing the DL_DISABMULTI_REQ parameters
  700. //
  701. //    Output:
  702. //        returns status of the call
  703. //
  704. //-----------------------------------------------------------------------------------------
  705. SInt32 DoDisableMulticast(DLPIStream *theStream, mblk_t *mp) 
  706. {
  707. dl_disabmulti_req_t*     req = (dl_disabmulti_req_t*)mp->b_rptr;
  708. UInt8                     *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
  709. mblk_t                     *mc;
  710.  
  711. if (GetAddressType(reqaddr) != keaMulticast) 
  712.     {
  713.     DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
  714.     return (kdlpiDONE);
  715.     }
  716.     
  717.     // find address and dequeue if found
  718. if ((mc = IsAddressRegistered(&theStream->multicastQueue,reqaddr,kTrue,kRxInterrupts)) != NULL)    
  719.     {
  720.     freemsg(mc);
  721.     ABCVendorUnregisterMulticast(reqaddr);    // turn off multicast addr if no one is using it
  722.  
  723.     if (theStream->multicastQueue.qHead == NULL)
  724.         theStream->streamFlags &= ~kAcceptMulticasts;    // no longer check multicast packets
  725.         
  726.     DoOKAck(theStream, mp, DL_DISABMULTI_REQ);
  727.     return (kdlpiDONE);
  728.     }
  729.  
  730. DoErrorAck(theStream, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
  731. return (kdlpiDONE);
  732. }
  733.  
  734. //-----------------------------------------------------------------------------------------
  735. //    Description:
  736. //        This routine handles the DL_ENABMULTI_REQ call to enable a multicast address
  737. //        for a certain stream.  The address is checked to make sure it is indeed a 
  738. //        multicast address.  Then a check is done to see if the address has already
  739. //        been registered.
  740. //
  741. //        If everything passes then an OK ack is sent to the client.  If not then an error
  742. //        ack is sent.
  743. //
  744. //    Input:
  745. //        theStream - the stream requesting the enable
  746. //        mp - message block containing the DL_ENABMULTI_REQ parameters
  747. //
  748. //    Output:
  749. //        returns status of the call
  750. //
  751. //-----------------------------------------------------------------------------------------
  752. SInt32 DoEnableMulticast(DLPIStream *theStream, mblk_t *mp) 
  753. {
  754.  
  755. dl_enabmulti_req_t*    req = (dl_enabmulti_req_t*)mp->b_rptr;
  756. UInt8                 *reqaddr = (UInt8 *)(mp->b_rptr + req->dl_addr_offset);
  757. mblk_t                 *mc;
  758. SInt32                 i;
  759.  
  760. if (GetAddressType(reqaddr) == keaMulticast)
  761.     {
  762.     if (IsAddressRegistered(&theStream->multicastQueue,reqaddr,kFalse,kRxInterrupts))    
  763.         {
  764.         DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
  765.         return (kdlpiDONE);
  766.         }
  767.         
  768.     if ((mc = allocb(kEnetPhysicalAddressLength, BPRI_HI)) == NULL) 
  769.         {
  770.         DoWriteScheduler(theStream, kEnetPhysicalAddressLength);
  771.         return(kdlpiRETRY);
  772.         }
  773.  
  774.     ABCVendorRegisterMulticast(reqaddr);
  775.         
  776.     for (i = 0; i < kEnetPhysicalAddressLength; i++)
  777.         *mc->b_wptr++ = *reqaddr++;
  778.  
  779.         // add new address to multicast list
  780.     EnqueueElement(&theStream->multicastQueue,(QElem *)mc,kBothTxRxInterrupts);    
  781.     
  782.     DoOKAck(theStream, mp, DL_ENABMULTI_REQ);
  783.     
  784.     theStream->streamFlags |= kAcceptMulticasts;    // on receive now check multicast packets
  785.     }
  786. else 
  787.     DoErrorAck(theStream, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
  788.     
  789. return (kdlpiDONE);
  790. }
  791.  
  792. //-----------------------------------------------------------------------------------------
  793. //    Description:
  794. //        This routine is used to enable the write queue.
  795. //
  796. //    Input:
  797. //        p - the stream that contains the write queue that needs to be enabled
  798. //
  799. //    Output:
  800. //        NONE
  801. //
  802. //-----------------------------------------------------------------------------------------
  803. void EnableWriteQueue(long p)
  804. {
  805. DLPIStream *theStream = (DLPIStream *)p;
  806.  
  807. if (theStream->readQueue) 
  808.     {
  809.     theStream->idType = NULL;    // mark us as no event waiting 
  810.     qenable(WR(theStream->readQueue));
  811.     }
  812. }
  813.  
  814. //-----------------------------------------------------------------------------------------
  815. //    Description:
  816. //        This routine builds and sends (if possible) an error ack for a particular call
  817. //        made by a client.  If memory cannot be allocated for the ack message block
  818. //        then a scheduled event is queued.
  819. //
  820. //    Input:
  821. //        theStream - the stream to send the error ack to
  822. //        ack_mp - the message block to use for the ack
  823. //        prim - the primitive or call that caused the error ack
  824. //        err - error number to be placed in the error ack message block
  825. //        uerr - the unix error number
  826. //
  827. //    Output:
  828. //        returns status of the call
  829. //
  830. //-----------------------------------------------------------------------------------------
  831. SInt32 DoErrorAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 prim, UInt32 err, UInt32 uerr)
  832. {
  833. dl_error_ack_t *errp;
  834.  
  835. if (ack_mp == NULL) 
  836.     {
  837.     if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) 
  838.         {
  839.         DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
  840.         return(kdlpiRETRY);
  841.         }
  842.     } 
  843. else     // so we have a message block
  844.     {
  845.     if (ack_mp->b_datap->db_ref != 1)    // is anybody else using this message data
  846.         {
  847.         freemsg(ack_mp);
  848.         if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) 
  849.             {
  850.             DoWriteScheduler(theStream, sizeof(dl_error_ack_t));
  851.             return(kdlpiRETRY);
  852.             }
  853.         } 
  854.     else    // we are the only ones using this message
  855.         {
  856.         ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
  857.         if (ack_mp->b_cont != NULL) 
  858.             {
  859.             freemsg(ack_mp->b_cont);
  860.             ack_mp->b_cont = NULL;
  861.             }
  862.         }
  863.     }
  864.     
  865. ack_mp->b_datap->db_type = M_PCPROTO;
  866. errp = (dl_error_ack_t *)ack_mp->b_wptr;
  867. errp->dl_primitive = DL_ERROR_ACK;
  868. errp->dl_error_primitive = prim;
  869. errp->dl_errno = err;
  870. errp->dl_unix_errno = uerr;
  871. ack_mp->b_wptr += sizeof(dl_error_ack_t);
  872. putnext(theStream->readQueue, ack_mp);
  873. return(kdlpiDONE);
  874. }
  875.  
  876. //-----------------------------------------------------------------------------------------
  877. //    Description:
  878. //        This routine checks if the stream has already been registered by a certain sap.
  879. //        The sap could also contain a snap.
  880. //
  881. //    Input:
  882. //        theStream - the stream used for checking the new sap
  883. //        sap - the sap plus possibly snap that is being checked to see if it is already
  884. //            registered
  885. //        len - the number of bytes valid in the sap
  886. //
  887. //    Output:
  888. //        returns kTrue if sap is already registered, returns kFalse if not registered
  889. //
  890. //-----------------------------------------------------------------------------------------
  891. SInt32 FindSnap(DLPIStream *theStream, UInt8 *sap, SInt32 len)
  892. {
  893. DLPIStream     *tempStream = (DLPIStream *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  894.  
  895. while (tempStream) 
  896.     {
  897.     if (tempStream->streamFlags & kSnapStream) 
  898.         {
  899.         if (CheckAddressMatch(sap, tempStream->snap, len))
  900.             return kTrue;
  901.         }
  902.     tempStream = tempStream->nextStream;
  903.     }
  904. return kFalse;        
  905. }
  906.  
  907. //-----------------------------------------------------------------------------------------
  908. //    Description:
  909. //        This routine classifies a packet into the different types of protocols.  For IPX
  910. //        we need both the source and destination SAPs to make a protocol determination.
  911. //
  912. //    Input:
  913. //        thePacket - a message block the contains the received packet
  914. //
  915. //    Output:
  916. //        returns type of packet
  917. //
  918. //-----------------------------------------------------------------------------------------
  919. UInt16 ClassifyPacketType(UInt16 primarySAP, UInt16 secondarySAP)
  920. {
  921.  
  922. if (primarySAP >= kMinDIXSAP)         
  923.     return kPktDIX;
  924.  
  925. if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP))
  926.     return kPktIPX;
  927.  
  928. if (primarySAP == kSNAPSAP)
  929.     return kPkt8022SNAP;
  930.  
  931. if (primarySAP <= k8022GlobalSAP)
  932.     return kPkt8022SAP;
  933.  
  934. return kPktUnknown;
  935. }
  936.  
  937. //-----------------------------------------------------------------------------------------
  938. //    Description:
  939. //        This routine extracts the sap information from the ethernet packet header.
  940. //
  941. //    Input:
  942. //        fullpkt - ptr to Ethernet packet header
  943. //        sourceSAP - return source sap here
  944. //        destSAP - return dest sap here
  945. //
  946. //    Output:
  947. //        NONE
  948. //
  949. //-----------------------------------------------------------------------------------------
  950. void ExtractSAPValues(T8022FullPacketHeader *fullpkt, UInt16 *sourceSAP, UInt16 *destSAP)
  951. {
  952.  
  953.  
  954. *destSAP = fullpkt->fEnetPart.fProto;
  955.  
  956. if (*destSAP >= kMinDIXSAP)        // classic ethernet
  957.     *sourceSAP = *destSAP;
  958. else
  959.     {
  960.     *destSAP = fullpkt->f8022Part.fDSAP;
  961.     *sourceSAP = fullpkt->f8022Part.fSSAP;
  962.     }
  963.  
  964. }
  965.  
  966. //-----------------------------------------------------------------------------------------
  967. //    Description:
  968. //        This routine checks each stream to see if it "wants" the packet.  In the loop
  969. //        each stream that wants the packet is placed in a linked list (queue).  After
  970. //        all the streams are examined then the packet is passed to each stream (while loop).  
  971. //        If more than 1 stream wants the packet then n-1 streams receive a dupmsg packet
  972. //        and the last stream receives the original.
  973. //
  974. //        In order to build the list we have to jump through some hoops so we don't have
  975. //        to allocate any memory.  In the DLPIStream struct a rxPacketLink follows
  976. //        the real link.  We use the rxPacketLink field to link the streams together.
  977. //        I should mention that the real link field keeps track of all the opened streams
  978. //        for this piece of hw.  So we build a list of streams that want the packet
  979. //        and then we walk the list and send the packet to each stream.  Since the
  980. //        rxPacketLink is not at the beginning of the DLPIStream structure we must
  981. //        subtract 4 from the value in the link to get back to the beginning of the 
  982. //        DLPIStream structure.
  983. //
  984. //        Now why do we jump through so many whoops?  Well we could just find a stream
  985. //        that wants the packet and then dupmsg to each stream.  After we exit the loop
  986. //        then just free the original message.  By doing all this fancy stuff we save
  987. //        doing the dupmsg for one stream, in fact if only 1 stream wants the packet
  988. //        then no duping is done.  So we save some memory and time by not duping if we
  989. //        don't have to.  Make sense?  Feel free to change it to the simpler method if
  990. //        you want.
  991. //        
  992. //    Input:
  993. //        theStream - the first stream in a list of streams that will be checked
  994. //        mp - a message block that contains the received packet
  995. //
  996. //    Output:
  997. //        NONE
  998. //
  999. //-----------------------------------------------------------------------------------------
  1000. void FindStreamForReceivedPacket(DLPIStream *theStream, mblk_t *mp)
  1001. {
  1002. EnetPacketHeader         *pkt = (EnetPacketHeader *)mp->b_rptr;
  1003. T8022FullPacketHeader    *fullpkt;
  1004. Boolean                 isOurs;
  1005. UInt16                     packetType,sourceSAP,destSAP;
  1006. mblk_t                     *copy_of_mp = NULL;
  1007. SInt32                     destAddressType;
  1008. QHdr                    wantsPacketQueue;
  1009. DLPIStream                 *fakeStream;
  1010.  
  1011.     // init queue for storing streams that want the rx packet
  1012. wantsPacketQueue.qHead = NULL;        
  1013. wantsPacketQueue.qTail = NULL;
  1014.  
  1015. fullpkt = (T8022FullPacketHeader *)pkt;
  1016.  
  1017. ExtractSAPValues(fullpkt,&sourceSAP, &destSAP);
  1018.  
  1019. packetType = ClassifyPacketType(sourceSAP,destSAP);
  1020.             
  1021. destAddressType = GetAddressType(pkt->fDestAddr);
  1022.  
  1023. for (; theStream; theStream = theStream->nextStream) 
  1024.     {
  1025.     isOurs = kFalse;
  1026.     if (theStream->dlpiState == DL_UNBOUND)     // can't send to unbound streams
  1027.         continue;
  1028.         
  1029.         // does this stream want all 802.2 packets?
  1030.     if ((theStream->streamFlags & kAcceptAll8022Packets) && (destSAP <= 0xff))    
  1031.         {
  1032.         EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
  1033.         continue;
  1034.         }
  1035.     
  1036.     if (destSAP == theStream->dlsap) 
  1037.         {
  1038.         if (theStream->streamFlags & kSnapStream)  // check SNAPs if necessary 
  1039.             isOurs = CheckAddressMatch(fullpkt->f8022Part.fSNAP, theStream->snap, 
  1040.                 k8022SNAPLength);
  1041.         else            // no SNAP, found a match since saps match 
  1042.             isOurs = kTrue;
  1043.         
  1044.         } 
  1045.     else     // Check for an 802.3 Group/Global (odd) 
  1046.         {
  1047.         if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP))
  1048.             && (destSAP & 1) && TestGroupSAP(theStream, destSAP))
  1049.             isOurs = kTrue;
  1050.         }
  1051.     
  1052.     if (!isOurs)    // this stream does not want this packet
  1053.         continue;
  1054.  
  1055.         // if this is a multicast packet, see if it is destined for an address we
  1056.          // are interested in
  1057.     if (isOurs && (destAddressType == keaMulticast) && 
  1058.             (theStream->streamFlags & kAcceptMulticasts)) 
  1059.         {
  1060.         isOurs = kFalse;        // assume no match 
  1061.         if (IsAddressRegistered(&theStream->multicastQueue,pkt->fDestAddr,kFalse, kNoInterrupts))    
  1062.             isOurs = kTrue;
  1063.         }
  1064.         
  1065.         // add stream to our list if it can accept the packet
  1066.     if (isOurs && canput(theStream->readQueue->q_next))
  1067.         EnqueueElement(&wantsPacketQueue,(QElem *)&theStream->rxPacketLink, kNoInterrupts);
  1068.     }
  1069.  
  1070.  
  1071.     // once all the streams that want this packet have been put on the queue we need
  1072.     //  to go through the streams list, when multiple streams want the packet all
  1073.     //  the streams get a duplicate except for the last stream which gets the original
  1074.     //  this saves an extra duplicate
  1075.  
  1076. /*zzz*/
  1077. if (wantsPacketQueue.qHead == NULL)
  1078.     DebugStrErr ((ConstStr255Param) "\pNo one wanted message");
  1079. else
  1080.     DebugStr1 ((ConstStr255Param) "\pSomeone wants this message");
  1081. /*zzz*/
  1082. if (wantsPacketQueue.qHead == NULL)
  1083.     freemsg(mp);    // nobody wanted the message (packet)
  1084. else
  1085.     {    // 1 or more streams want this packet
  1086.     fakeStream = (DLPIStream *)wantsPacketQueue.qHead;
  1087.     theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
  1088.     while (theStream->rxPacketLink)
  1089.         {
  1090.         if ((copy_of_mp = dupmsg(mp)) != NULL)
  1091.             HandleReceivedPacket(theStream, copy_of_mp,packetType);
  1092.         fakeStream = theStream->rxPacketLink;
  1093.         theStream = (DLPIStream *)(((UInt8 *)fakeStream) - sizeof(DLPIStream *));
  1094.         }
  1095.     HandleReceivedPacket(theStream, mp,packetType);    // send original
  1096.     }
  1097.         
  1098. }
  1099.  
  1100. //-----------------------------------------------------------------------------------------
  1101. //    Description:
  1102. //         This routine handles the info primitive/call from the client.  The information is
  1103. //        collected from the DLPI and then placed in a message block that will be returned
  1104. //        to the client.
  1105. //
  1106. //    Input:
  1107. //        theStream - the stream from which the information is collected
  1108. //
  1109. //    Output:
  1110. //        returns status of the call
  1111. //
  1112. //-----------------------------------------------------------------------------------------
  1113. SInt32 DoGeneralInfo(DLPIStream *theStream)
  1114. {
  1115. dl_info_ack_t    *ackp;
  1116. mblk_t             *ack_mp;
  1117. UInt32             saplen = 0;
  1118. UInt32             addrlen = kEnetPhysicalAddressLength;
  1119. UInt32             bcastlen = kEnetPhysicalAddressLength;
  1120. UInt32             hdrlen = kEnetPacketHeaderLength;
  1121. T8022AddressStruct    *boundAddr;    
  1122.  
  1123. if (theStream->dlpiState != DL_UNBOUND) 
  1124.     {
  1125.     saplen = (theStream->streamFlags & kSnapStream) 
  1126.         ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength;
  1127.  
  1128.     if (theStream->dlsap == kSNAPSAP)     
  1129.         hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength;    // SNAP address 
  1130.     else if ((theStream->dlsap <= kMax8022SAP) || (theStream->dlsap == kIPXSAP))
  1131.         hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength;    // SAP or IPX 
  1132.     else                                
  1133.         hdrlen = kEnetPacketHeaderLength;    // basic Ethernet
  1134.     }
  1135.  
  1136. if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL)
  1137.     {
  1138.     DoWriteScheduler(theStream, sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen);
  1139.     return(kdlpiRETRY);
  1140.     }
  1141.  
  1142. ack_mp->b_datap->db_type = M_PCPROTO;
  1143. ackp = (dl_info_ack_t *)ack_mp->b_rptr;
  1144.  
  1145. if ( theStream->streamFlags & kReadRawPackets )
  1146.     ackp->dl_max_sdu = kEnetTSDU;        // for raw packet mode
  1147. else
  1148.     ackp->dl_max_sdu = kEnetTSDU - hdrlen;
  1149.  
  1150. ackp->dl_min_sdu = 1;
  1151. ackp->dl_addr_length = addrlen + saplen;
  1152. ackp->dl_mac_type = (gDLPIPrivateData->privateFlags & kpfFraming8022) ? DL_CSMACD : DL_ETHER;
  1153. ackp->dl_reserved = 0;
  1154. ackp->dl_sap_length = -saplen;        // negative to indicate sap follows physical address
  1155. ackp->dl_service_mode = DL_CLDLS;
  1156. ackp->dl_qos_length = 0;
  1157. ackp->dl_qos_offset = DL_UNKNOWN;
  1158. ackp->dl_qos_range_length = 0;
  1159. ackp->dl_qos_range_offset = DL_UNKNOWN;
  1160. ackp->dl_provider_style = DL_STYLE1;
  1161. ackp->dl_addr_offset = sizeof(dl_info_ack_t);
  1162. ackp->dl_version = DL_VERSION_2;
  1163. ackp->dl_brdcst_addr_length = bcastlen;
  1164. ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen;
  1165. ackp->dl_growth = 0;
  1166. ackp->dl_primitive = DL_INFO_ACK;
  1167. ackp->dl_current_state = theStream->dlpiState;
  1168. ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen;
  1169.  
  1170. boundAddr = ((T8022AddressStruct*)(ack_mp->b_rptr + ackp->dl_addr_offset));
  1171.  
  1172. OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress,boundAddr->fHWAddr);
  1173. if (saplen)
  1174.     {
  1175.     boundAddr->fSAP = theStream->dlsap;
  1176.     if (theStream->streamFlags & kSnapStream) 
  1177.         OTCopy8022SNAP(theStream->snap, boundAddr->fSNAP);
  1178.     }
  1179.     
  1180. OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset);    
  1181.  
  1182. putnext(theStream->readQueue, ack_mp);
  1183. return (kdlpiDONE);
  1184. }
  1185.  
  1186. //-----------------------------------------------------------------------------------------
  1187. //    Description:
  1188. //        This is a utility routine that compares to address (byte arrays).  
  1189. //
  1190. //    Input:
  1191. //        a - address array 1
  1192. //        b - address array 2
  1193. //        len - number of bytes that should match in the arrays
  1194. //
  1195. //    Output:
  1196. //        returns kTrue if they match and kFalse if they do not
  1197. //
  1198. //-----------------------------------------------------------------------------------------
  1199. Boolean CheckAddressMatch(UInt8 *a, UInt8 *b, SInt32 len)
  1200. {
  1201. register SInt32 i;
  1202.  
  1203. for (i = 0; i < len; i++) 
  1204.     {
  1205.     if (*a++ != *b++)
  1206.         return kFalse;
  1207.     }
  1208.  
  1209. return kTrue;
  1210. }
  1211.  
  1212. //-----------------------------------------------------------------------------------------
  1213. //    Description:
  1214. //        This routine fills in the ok ack message block and then passes it to the client.
  1215. //
  1216. //    Input:
  1217. //        theStream - the stream that will be passed the ok ack
  1218. //        ack_mp - ok ack message block
  1219. //        primitive - call that is being ack'd
  1220. //
  1221. //    Output:
  1222. //        NONE
  1223. //
  1224. //-----------------------------------------------------------------------------------------
  1225. void DoOKAck(DLPIStream *theStream, mblk_t *ack_mp, UInt32 primitive)
  1226. {
  1227. dl_ok_ack_t *ackp;
  1228.  
  1229. ack_mp->b_datap->db_type = M_PCPROTO;
  1230. ack_mp->b_rptr = ack_mp->b_wptr = ack_mp->b_datap->db_base;
  1231. ackp = (dl_ok_ack_t *)ack_mp->b_wptr;
  1232. ackp->dl_primitive = DL_OK_ACK;
  1233. ackp->dl_correct_primitive = primitive;
  1234. ack_mp->b_wptr += sizeof(dl_ok_ack_t);
  1235. putnext(theStream->readQueue, ack_mp);
  1236. }
  1237.  
  1238. //-----------------------------------------------------------------------------------------
  1239. //    Description:
  1240. //        This routine acks the get physical address (ethernet) call from the client.
  1241. //        An ack message block is built and filled in.  If this message block cannot
  1242. //        be allocated then a scheduler task is queued.
  1243. //
  1244. //    Input:
  1245. //        theStream - the stream requesting the physical address information
  1246. //        mp - the message block requesting the physical address
  1247. //
  1248. //    Output:
  1249. //        returns status of the call
  1250. //
  1251. //-----------------------------------------------------------------------------------------
  1252. SInt32 DoPhysicalAddressAck(DLPIStream *theStream, mblk_t *mp) 
  1253. {
  1254. mblk_t                 *ack_mp;
  1255. dl_phys_addr_ack_t    *ackp;
  1256. dl_phys_addr_req_t     *addrReq = (dl_phys_addr_req_t *)mp->b_rptr;
  1257. UInt8                addressArray[kEnetPhysicalAddressLength];
  1258.  
  1259. if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) 
  1260.     {
  1261.     DoWriteScheduler(theStream, DL_PHYS_ADDR_ACK_SIZE + kEnetPhysicalAddressLength);
  1262.     return(kdlpiRETRY);
  1263.     }
  1264.     
  1265. ack_mp->b_datap->db_type = M_PCPROTO;
  1266. ackp = (dl_phys_addr_ack_t *)ack_mp->b_wptr;
  1267. ackp->dl_primitive = DL_PHYS_ADDR_ACK;
  1268. ackp->dl_addr_length = kEnetPhysicalAddressLength;
  1269. ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
  1270. ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength;
  1271. switch(addrReq->dl_addr_type)
  1272.     {
  1273.     case DL_CURR_PHYS_ADDR:
  1274.         OTCopy48BitAddress(&gDLPIPrivateData->ourEAddress, 
  1275.             ack_mp->b_rptr + ackp->dl_addr_offset);
  1276.         break;
  1277.     case DL_FACT_PHYS_ADDR:
  1278.         ABCVendorGetFactoryEthernetAddress(addressArray);
  1279.         OTCopy48BitAddress(addressArray, ack_mp->b_rptr + ackp->dl_addr_offset);
  1280.         break;
  1281.     default:
  1282.         break;
  1283.     }
  1284.  
  1285. putnext(theStream->readQueue, ack_mp);
  1286. return(kdlpiDONE);
  1287. }
  1288.  
  1289. //-----------------------------------------------------------------------------------------
  1290. //    Description:
  1291. //        This routine is NOT finished yet.  The statistics will be returned through this
  1292. //        call, but the format of the structure(s) has not been determined.  The code
  1293. //        that calls this routine (WriteServiceRoutine) has been commented out so this
  1294. //        routine will never get called.  I added this routine so that it is a placeholder
  1295. //        for when the decision has been made on how to return the statistics.
  1296. //
  1297. //    Input:
  1298. //        theStream - the stream requesting the physical address information
  1299. //        mp - the message block requesting the statistics
  1300. //
  1301. //    Output:
  1302. //        returns status of the call
  1303. //
  1304. //-----------------------------------------------------------------------------------------
  1305. SInt32 DoStatisticsAck(DLPIStream *theStream, mblk_t *mp) 
  1306. {
  1307. mblk_t                     *ack_mp;
  1308. dl_get_statistics_ack_t    *statAckStruct;
  1309. UInt16                    statSize;
  1310.  
  1311. statSize = 100;        // this is not a valid number, just a number that lets us compile
  1312.  
  1313. if ((ack_mp = allocb(sizeof(dl_get_statistics_ack_t) + statSize, BPRI_HI)) == NULL) 
  1314.     {
  1315.     DoWriteScheduler(theStream, sizeof(dl_get_statistics_ack_t) + statSize);
  1316.     return(kdlpiRETRY);
  1317.     }
  1318.     
  1319. ack_mp->b_datap->db_type = M_PCPROTO;
  1320. statAckStruct = (dl_get_statistics_ack_t *)ack_mp->b_wptr;
  1321. statAckStruct->dl_primitive = DL_GET_STATISTICS_ACK;
  1322.  
  1323. statAckStruct->dl_stat_length = statSize;
  1324. statAckStruct->dl_stat_offset = sizeof(dl_get_statistics_ack_t);
  1325. ack_mp->b_wptr += sizeof(dl_get_statistics_ack_t) + statSize;
  1326.  
  1327.  
  1328. // WE NEED TO COPY OUR STATISTICS TO THE MESSAGE BLOCK
  1329.  
  1330.  
  1331. putnext(theStream->readQueue, ack_mp);
  1332. return(kdlpiDONE);
  1333.  
  1334. }
  1335.  
  1336. //-----------------------------------------------------------------------------------------
  1337. //    Description:
  1338. //        This routine accepts subsbind primitives.  A subsbind is used to register
  1339. //        802.2 SAP group addresses and snaps.  snaps can only be bound to a stream
  1340. //        that has a dlsap of 0xAA.
  1341. //
  1342. //            DL_PEER_BIND - for group addresses
  1343. //            DL_HIERARCHICAL_BIND - for additional snaps
  1344. //
  1345. //    Input:
  1346. //        theStream - the stream being bound
  1347. //        mp - the message block containing the subsbind parameters
  1348. //
  1349. //    Output:
  1350. //        returns status of the call
  1351. //
  1352. //-----------------------------------------------------------------------------------------
  1353. SInt32  SubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1354. {
  1355. dl_subs_bind_req_t     *req = (dl_subs_bind_req_t *)mp->b_rptr;
  1356. mblk_t                 *ack_mp;
  1357. UInt8                 *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
  1358. SInt32                 length = req->dl_subs_sap_length;
  1359. UInt16                 theSap;
  1360. SInt32                 error = kOTNoError;
  1361.  
  1362. if (theStream->dlpiState != DL_IDLE) 
  1363.     return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0));
  1364.  
  1365. theSap = *((UInt16 *)sap);
  1366.  
  1367. switch(req->dl_subs_bind_class)
  1368.     {
  1369.     case DL_PEER_BIND:
  1370.         if (theStream->dlsap <= kMax8022SAP) 
  1371.             {
  1372.             if ((theSap & 1) && (length == sizeof(theSap)))
  1373.                 SetGroupSAP(theStream, theSap);
  1374.             else
  1375.                 if (theSap == 0x0000)    // special case to receive all 802.2 packets
  1376.                     theStream->streamFlags |= kAcceptAll8022Packets;
  1377.                 else
  1378.                     error = DL_BADADDR;
  1379.             } 
  1380.         else
  1381.             error = DL_UNSUPPORTED;
  1382.         break;    
  1383.     
  1384.     case DL_HIERARCHICAL_BIND:    
  1385.         if (theStream->dlsap == kSNAPSAP)
  1386.             {
  1387.             if (theStream->streamFlags & kSnapStream) 
  1388.                 error = DL_TOOMANY;    // only one SNAP binding allowed 
  1389.             else
  1390.                 {
  1391.                 OTCopy8022SNAP(sap, theStream->snap);
  1392.                 theStream->streamFlags |= kSnapStream;
  1393.                 }
  1394.             }
  1395.         else
  1396.             error = DL_BADADDR;
  1397.         break;
  1398.         
  1399.     default:
  1400.         error = DL_UNSUPPORTED;
  1401.         break;
  1402.     }
  1403.     
  1404.  
  1405. if (error) 
  1406.     return( DoErrorAck(theStream, mp, DL_SUBS_BIND_REQ, error, 0));
  1407.  
  1408. if ((ack_mp = BuildSubsBindAck(theStream, sap, length)) == NULL)
  1409.     return (kdlpiRETRY);
  1410.  
  1411. freemsg(mp);
  1412. theStream->dlpiState = DL_IDLE;
  1413. putnext(theStream->readQueue, ack_mp);
  1414. return(kdlpiDONE);
  1415. }
  1416.  
  1417. //-----------------------------------------------------------------------------------------
  1418. //    Description:
  1419. //        This routine builds the ack for the subsbind call.  If the ack message block
  1420. //        cannot be scheduled then a task is queued.
  1421. //
  1422. //    Input:
  1423. //        theStream - the stream that will be sent the subsbind ack
  1424. //        sap - the sap to be returned in the ack mb
  1425. //        length - number of valid bytes in the sap
  1426. //
  1427. //    Output:
  1428. //        returns ack message block
  1429. //
  1430. //-----------------------------------------------------------------------------------------
  1431. mblk_t *BuildSubsBindAck(DLPIStream *theStream, UInt8 *sap, SInt32 length)
  1432. {
  1433. dl_subs_bind_ack_t    *ackp;
  1434. mblk_t                 *mp;
  1435.  
  1436. if ((mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) 
  1437.     {
  1438.     DoWriteScheduler(theStream, sizeof(dl_subs_bind_ack_t) + length);
  1439.     return(NULL);
  1440.     }
  1441.     
  1442. mp->b_datap->db_type = M_PCPROTO;
  1443. ackp = (dl_subs_bind_ack_t *)mp->b_wptr;
  1444. bzero(ackp, sizeof(dl_subs_bind_ack_t) + length);
  1445. ackp->dl_primitive = DL_SUBS_BIND_ACK;
  1446. ackp->dl_subs_sap_length = length;
  1447. ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0;
  1448. mp->b_wptr += sizeof(dl_subs_bind_ack_t);
  1449. if (length)
  1450.     bcopy(sap, mp->b_wptr, length);
  1451. mp->b_wptr += length;
  1452.  
  1453. return(mp);
  1454. }
  1455.  
  1456. //-----------------------------------------------------------------------------------------
  1457. //    Description:
  1458. //        This routine handles changing the Ethernet address of the card.  All streams 
  1459. //        opened on this port must be in the unbound state.  The address length must
  1460. //        be equal to the Ethernet physical length.
  1461. //
  1462. //    Input:
  1463. //        theStream - the stream requesting the new physical address
  1464. //        mp - the message block containing the physical address
  1465. //
  1466. //    Output:
  1467. //        returns status of the call
  1468. //
  1469. //-----------------------------------------------------------------------------------------
  1470. SInt32 DoSetPhysicalAddress(DLPIStream *theStream, mblk_t *mp)
  1471. {
  1472. dl_set_phys_addr_req_t     *req = (dl_set_phys_addr_req_t *)mp->b_rptr;
  1473. SInt32                     length = req->dl_addr_length;
  1474. mblk_t                     *ack_mp;
  1475. UInt8                    *physicalAddress = ((UInt8 *)req) + req->dl_addr_offset;
  1476.  
  1477.  
  1478. if (!AreAllStreamsUnbound())         // all streams must be unbound, if error abort
  1479.     {
  1480.     if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1481.         return(kdlpiRETRY);
  1482.     freemsg(mp);
  1483.     return(kdlpiDONE);
  1484.     }
  1485.  
  1486. if (length != kEnetPhysicalAddressLength)     // must only contain Ethernet address
  1487.     {
  1488.     if (DoErrorAck(theStream, 0, DL_SET_PHYS_ADDR_REQ, DL_BADADDR, 0) == kdlpiRETRY)
  1489.         return(kdlpiRETRY);
  1490.     freemsg(mp);
  1491.     return(kdlpiDONE);
  1492.     }
  1493.     
  1494. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1495.     {
  1496.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1497.     return(kdlpiRETRY);
  1498.     }
  1499.  
  1500. ABCVendorSetEthernetAddress(physicalAddress);
  1501.  
  1502. freemsg(mp);
  1503.  
  1504. DoOKAck(theStream, ack_mp, DL_SET_PHYS_ADDR_REQ);
  1505.     
  1506. return(kdlpiDONE);
  1507. }
  1508.  
  1509. //-----------------------------------------------------------------------------------------
  1510. //    Description:
  1511. //        This routine handles the unsubsbind primitive/call.  A snap can be unbound and
  1512. //        also a 802.2 group address.  An ok ack message block is sent to the client
  1513. //        if everything goes well and error ack if not.
  1514. //
  1515. //    Input:
  1516. //        theStream - the stream requesting the unsubsbind
  1517. //        mp - the message block containing the unsubsbind parameters
  1518. //
  1519. //    Output:
  1520. //        returns status of the call
  1521. //
  1522. //-----------------------------------------------------------------------------------------
  1523. SInt32 UnSubsBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1524. {
  1525. dl_subs_unbind_req_t     *req = (dl_subs_unbind_req_t *)mp->b_rptr;
  1526. UInt8                     *sap = ((UInt8 *)req) + req->dl_subs_sap_offset;
  1527. SInt32                     length = req->dl_subs_sap_length;
  1528. mblk_t                     *ack_mp;
  1529. SInt32                     error = 0;
  1530.  
  1531. if (theStream->dlpiState != DL_IDLE) 
  1532.     {
  1533.     if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1534.         return(kdlpiRETRY);
  1535.     freemsg(mp);
  1536.     return(kdlpiDONE);
  1537.     }
  1538.     
  1539. if (length == k8022SAPLength) 
  1540.     {
  1541.     if ((*sap & 1) && (*sap != kIPXSAP)) 
  1542.         {
  1543.         if (theStream->dlsap <= kMax8022SAP)
  1544.             ClearGroupSAP(theStream, *sap);
  1545.         else
  1546.             error = DL_UNSUPPORTED;
  1547.         } 
  1548.     else
  1549.         error = DL_BADADDR;
  1550.     } 
  1551. else 
  1552.     if (length == k8022SNAPLength) 
  1553.     {
  1554.     if (theStream->dlsap == kSNAPSAP) 
  1555.         {
  1556.         if (theStream->streamFlags & kSnapStream) 
  1557.             {
  1558.             if (CheckAddressMatch(theStream->snap, sap, length) == kFalse) 
  1559.                 error = DL_BADADDR;
  1560.             } 
  1561.         else
  1562.             error = DL_BADADDR;
  1563.         } 
  1564.     else
  1565.         error = DL_UNSUPPORTED;
  1566.     }
  1567.  
  1568. if (error) 
  1569.     {
  1570.     if (DoErrorAck(theStream, 0, DL_SUBS_UNBIND_REQ, error, 0) == kdlpiRETRY)
  1571.         return(kdlpiRETRY);
  1572.     freemsg(mp);
  1573.     return(kdlpiDONE);
  1574.     }
  1575.     
  1576. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1577.     {
  1578.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1579.     return(kdlpiRETRY);
  1580.     }
  1581.     
  1582. freemsg(mp);
  1583. theStream->streamFlags &= ~kSnapStream;
  1584. DoOKAck(theStream, ack_mp, DL_SUBS_UNBIND_REQ);
  1585.  
  1586. return(kdlpiDONE);
  1587. }
  1588.  
  1589. //-----------------------------------------------------------------------------------------
  1590. //    Description:
  1591. //        This routine if called when the client wishes to unbind the stream.  An ok ack is
  1592. //        sent to the client if everything goes well.
  1593. //
  1594. //    Input:
  1595. //        theStream - the stream being unbound
  1596. //        mp - the message block containing the unbind message
  1597. //
  1598. //    Output:
  1599. //        returns status of the call
  1600. //
  1601. //-----------------------------------------------------------------------------------------
  1602. SInt32 UnBindTheStream(DLPIStream *theStream, mblk_t *mp)
  1603. {
  1604. mblk_t *ack_mp;
  1605.  
  1606. if (theStream->dlpiState != DL_IDLE) 
  1607.     {
  1608.     if (DoErrorAck(theStream, 0, DL_UNBIND_REQ, DL_OUTSTATE, 0) == kdlpiRETRY)
  1609.         return(kdlpiRETRY);
  1610.     freemsg(mp);
  1611.     return(kdlpiDONE);
  1612.     }
  1613.  
  1614. if ((ack_mp = allocb(DL_OK_ACK_SIZE, BPRI_HI)) == NULL) 
  1615.     {
  1616.     DoWriteScheduler(theStream, DL_OK_ACK_SIZE);
  1617.     return(kdlpiRETRY);
  1618.     }
  1619.     
  1620. freemsg(mp);
  1621.  
  1622. //if (putctl1(theStream->readQueue->q_next, M_FLUSH, FLUSHRW) == 0)
  1623.  
  1624. theStream->dlpiState = DL_UNBOUND;
  1625. theStream->dlsap = 0;                
  1626. DoOKAck(theStream, ack_mp, DL_UNBIND_REQ);
  1627. return(kdlpiDONE);
  1628. }
  1629.  
  1630. //-----------------------------------------------------------------------------------------
  1631. //    Description:
  1632. //        This utility routine sets a bit in the group sap array that indicates if a 
  1633. //        certain group sap has been bound (subsbind).
  1634. //
  1635. //    Input:
  1636. //        theStream - the stream for the group sap
  1637. //        sap - group sap that needs registration bit set
  1638. //
  1639. //    Output:
  1640. //        NONE
  1641. //
  1642. //-----------------------------------------------------------------------------------------
  1643. void SetGroupSAP(DLPIStream *theStream, UInt8 sap) 
  1644. {
  1645. theStream->group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask));
  1646. }
  1647.  
  1648. //-----------------------------------------------------------------------------------------
  1649. //    Description:
  1650. //        This utility routine is used to clear a registration bit for a certain sap.
  1651. //
  1652. //    Input:
  1653. //        theStream - the stream for the group sap
  1654. //        sap - group sap that needs registration bit cleared
  1655. //
  1656. //    Output:
  1657. //        NONE
  1658. //
  1659. //-----------------------------------------------------------------------------------------
  1660. void ClearGroupSAP(DLPIStream *theStream, UInt8 sap)
  1661. {
  1662. theStream->group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask));
  1663. }
  1664.  
  1665. //-----------------------------------------------------------------------------------------
  1666. //    Description:
  1667. //        This utility routine tests a registration bit against a sap.  
  1668. //
  1669. //    Input:
  1670. //        theStream - the stream for the group sap
  1671. //        sap - group sap that needs checking
  1672. //
  1673. //    Output:
  1674. //        returns kTrue is sap is registered, kFalse if not
  1675. //
  1676. //-----------------------------------------------------------------------------------------
  1677. Boolean TestGroupSAP(DLPIStream *theStream, UInt8 sap) 
  1678. {
  1679. return 0 != (theStream->group_sap[sap >> kGSshift] & (1L << ((sap >> 1) & kGSmask)));
  1680. }
  1681.  
  1682. //-----------------------------------------------------------------------------------------
  1683. //    Description:
  1684. //        This routine builds the uderror message block and sends it to the stream's client.
  1685. //
  1686. //    Input:
  1687. //        theStream - the stream sending the message block
  1688. //        dest - the destination address
  1689. //        destlen - number of bytes valid in dest parameter
  1690. //        err - error to retrun in the message block
  1691. //        uerr - unix error returned in the message block
  1692. //
  1693. //    Output:
  1694. //        NONE
  1695. //
  1696. //-----------------------------------------------------------------------------------------
  1697. void DoUdError(DLPIStream *theStream, UInt8 *dest, UInt32 destlen, UInt32 err, 
  1698.      UInt32 uerr)
  1699. {
  1700. dl_uderror_ind_t    *errp;
  1701. mblk_t                 *bp;
  1702. SInt32                 i;
  1703.  
  1704. i = sizeof(dl_uderror_ind_t) + destlen;
  1705. if ((bp = allocb(i, BPRI_HI)) == NULL)
  1706.     return;
  1707. bp->b_datap->db_type = M_PROTO;
  1708. errp = (dl_uderror_ind_t *)bp->b_wptr;
  1709. errp->dl_primitive = DL_UDERROR_IND;
  1710. errp->dl_errno = err;
  1711. errp->dl_unix_errno = uerr;
  1712. errp->dl_dest_addr_length = destlen;
  1713. errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
  1714. bp->b_wptr += sizeof(dl_uderror_ind_t);
  1715. bcopy((UInt8 *)dest, (UInt8 *)bp->b_wptr, destlen);
  1716. bp->b_wptr += destlen;
  1717. putnext(theStream->readQueue, bp);
  1718. }
  1719.  
  1720. //-----------------------------------------------------------------------------------------
  1721. //    Description:
  1722. //        This routine is called when someone cannot allocate a message block for an ok ack
  1723. //        or error ack.  This routine says call me when you have enough memory for my
  1724. //        message block.
  1725. //
  1726. //    Input:
  1727. //        theStream - the stream to disable until memory is available
  1728. //        size - number of bytes needed for the message block
  1729. //
  1730. //    Output:
  1731. //        NONE
  1732. //
  1733. //-----------------------------------------------------------------------------------------
  1734. void DoWriteScheduler(DLPIStream *theStream, SInt32 size)
  1735. {
  1736.  
  1737. theStream->timeoutID = bufcall(size, BPRI_HI, EnableWriteQueue, (SInt32)theStream);
  1738. if (theStream->timeoutID) 
  1739.     theStream->idType = kdlpiBufcallType;
  1740. else 
  1741.     if ((*((UInt32 *)theStream->bufferTimerMsg->b_rptr)) == NULL)    // is timer unused?
  1742.         {
  1743.         *((UInt32 *)(theStream->bufferTimerMsg->b_rptr)) = kEnableQueueTimerMsg;
  1744.         mi_timer(theStream->bufferTimerMsg,500);    // send us a timer message in 1/2 sec
  1745.         }
  1746. }
  1747.  
  1748. //-----------------------------------------------------------------------------------------
  1749. //    Description:
  1750. //        This routine checks if all the streams are in the unbound state.
  1751. //
  1752. //    Input:
  1753. //        NONE
  1754. //
  1755. //    Output:
  1756. //        kTrue, if all the streams are unbound
  1757. //        kFalse, if some stream is not in the unbound state
  1758. //
  1759. //-----------------------------------------------------------------------------------------
  1760.  
  1761. Boolean AreAllStreamsUnbound(void)
  1762. {
  1763. mblk_t    *mbWalker;
  1764. Boolean    unbound = kTrue;
  1765.  
  1766. mbWalker = (mblk_t *)gDLPIPrivateData->dlpiStreamsQueue.qHead;
  1767.  
  1768. while (mbWalker && unbound) 
  1769.     {
  1770.     if (((DLPIStream *)mbWalker)->dlpiState == DL_UNBOUND)
  1771.         mbWalker = mbWalker->b_next;
  1772.     else
  1773.         unbound = kFalse;
  1774.     }
  1775.     
  1776. return unbound;
  1777. }
  1778.  
  1779. //-----------------------------------------------------------------------------------------
  1780. //    Description:
  1781. //        This routine processes a message block that contains a packet that needs to
  1782. //        be transmitted over the wire.  Error ack message blocks are sent to the
  1783. //        client if errors appear during processing.
  1784. //
  1785. //    Input:
  1786. //        theStream - the stream requesting the packet transmission
  1787. //        mp - the message block containing the packet
  1788. //
  1789. //    Output:
  1790. //        NONE
  1791. //
  1792. //-----------------------------------------------------------------------------------------
  1793. void DoUnitData(DLPIStream *theStream, mblk_t *mp)
  1794. {
  1795.  
  1796. dl_unitdata_req_t*    req;
  1797.  
  1798. req = (dl_unitdata_req_t *)mp->b_rptr;
  1799.  
  1800. if (theStream->dlpiState != DL_IDLE) 
  1801.     {
  1802.     DoUdError(theStream, ((UInt8 *)req) +  req->dl_dest_addr_offset, 
  1803.         req->dl_dest_addr_length, DL_OUTSTATE, 0);
  1804.     freemsg(mp);
  1805.     return;
  1806.     }
  1807.     
  1808. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1809.     PreparePacketToBeSent(mp);
  1810.     
  1811. }
  1812.  
  1813. //-----------------------------------------------------------------------------------------
  1814. //    Description:
  1815. //        This routine sends Test requests and responses.  The test primitives are only
  1816. //        valid on 802.2 streams.  A request packet should not be sent if the client
  1817. //        requested auto handling of the test messages.
  1818. //
  1819. //    Input:
  1820. //        theStream - the stream that wants to send the test
  1821. //        mp - message block that contains the data to send
  1822. //        requestFlag - kTrue if mp is a test request, kFalse if mp is a test response
  1823. //
  1824. //    Output:
  1825. //        NONE
  1826. //
  1827. //-----------------------------------------------------------------------------------------
  1828. SInt32 SendTestPacket(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
  1829. {                
  1830. Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
  1831.  
  1832. if (!is8022)
  1833.     {
  1834.     freemsg(mp);
  1835.     return kdlpiDONE;
  1836.     }
  1837.  
  1838. if (requestFlag && (theStream->streamFlags & kAutoTest))
  1839.     return( DoErrorAck(theStream, mp, DL_TEST_REQ, DL_TESTAUTO, 0));
  1840.  
  1841. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1842.     PreparePacketToBeSent(mp);
  1843.     
  1844. return kdlpiDONE;
  1845. }
  1846.  
  1847. //-----------------------------------------------------------------------------------------
  1848. //    Description:
  1849. //        This routine sends XID requests and responses.  The XID primitives are only
  1850. //        valid on 802.2 streams.  A request packet should not be sent if the client
  1851. //        requested auto handling of the XID messages.
  1852. //
  1853. //    Input:
  1854. //        theStream - the stream that wants to send the XID
  1855. //        mp - message block that contains the data to send
  1856. //        requestFlag - kTrue if mp is a XID request, kFalse if mp is a XID response
  1857. //
  1858. //    Output:
  1859. //        NONE
  1860. //
  1861. //-----------------------------------------------------------------------------------------
  1862. SInt32 DoXID(DLPIStream *theStream, mblk_t *mp, UInt8 requestFlag)
  1863. {                
  1864. Boolean is8022 = (theStream->dlsap <= kMax8022SAP);
  1865.  
  1866. if (!is8022)
  1867.     {
  1868.     freemsg(mp);
  1869.     return kdlpiDONE;
  1870.     }
  1871.  
  1872. if (requestFlag && (theStream->streamFlags & kAutoTest))
  1873.     return( DoErrorAck(theStream, mp, DL_XID_REQ, DL_XIDAUTO, 0));
  1874.  
  1875. if ((mp = BuildTxPacketHeader(theStream, mp, kFalse)) != NULL)
  1876.     PreparePacketToBeSent(mp);
  1877.  
  1878. return kdlpiDONE;
  1879. }
  1880.  
  1881. //-----------------------------------------------------------------------------------------
  1882. //    Description:
  1883. //         This routine builds the header block for Test/XID Indication/confirm packets.
  1884. //        So this routine can receive 4 types of packets for which it must build
  1885. //        a correct header so that the entire message can be passed up to our client.
  1886. //
  1887. //        The headers for each of the different types of packets is exactly the
  1888. //        same so we will just us the test indication structure for all the packet
  1889. //        types.
  1890. //
  1891. //    Input:
  1892. //        mp - message block that contains the info for building a test message
  1893. //        dlsap_length - the number of bytes in the mp message block 
  1894. //
  1895. //    Output:
  1896. //        NONE
  1897. //
  1898. //-----------------------------------------------------------------------------------------
  1899. void    BuildXidTestConfirmIndication(DLPIStream *theStream, mblk_t *mp, 
  1900.         UInt16 destAddrLength, UInt16 headerHideLength)
  1901. {
  1902. UInt32             primitive;
  1903. mblk_t             *nmp;
  1904. dl_test_ind_t*     ind;
  1905. UInt8             ssap = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fSSAP;
  1906. UInt8             ctrl = ((T8022FullPacketHeader *)(mp->b_rptr))->f8022Part.fCtrl;
  1907. T8022FullPacketHeader    *packetHeader;
  1908. T8022AddressStruct        *srcAddr,*destAddr;
  1909.  
  1910. if ((ctrl & 0xEF) == 0xE3)
  1911.     primitive = (ssap & 1) ? DL_TEST_CON : DL_TEST_IND;
  1912. else if ((ctrl & 0xEF) == 0xAF)
  1913.     primitive = (ssap & 1) ? DL_XID_CON : DL_XID_IND;
  1914. else
  1915.     return;
  1916.  
  1917.     //    Allocate a dl_test_(ind,con,xid)_t message, and fill it in.
  1918. if ((nmp = allocb(sizeof(dl_test_ind_t) + (destAddrLength * 2), BPRI_HI)) == NULL)
  1919.     {
  1920.     freemsg(mp);
  1921.     return;
  1922.     }
  1923.     
  1924. nmp->b_datap->db_type = M_PROTO;
  1925. ind = (dl_test_ind_t*)nmp->b_rptr;
  1926. ind->dl_primitive = primitive;
  1927. ind->dl_flag = (ctrl & 0x10) ? DL_POLL_FINAL : 0;
  1928. ind->dl_dest_addr_length = destAddrLength;
  1929. ind->dl_dest_addr_offset = sizeof(dl_test_ind_t);
  1930. ind->dl_src_addr_length = destAddrLength;
  1931. ind->dl_src_addr_offset = sizeof(dl_test_ind_t) + destAddrLength;
  1932. nmp->b_wptr += (sizeof(dl_test_ind_t) + destAddrLength + destAddrLength);
  1933.  
  1934. packetHeader = (T8022FullPacketHeader *)mp->b_rptr;
  1935.  
  1936. destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
  1937. srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
  1938.  
  1939. BuildRxDestSrcHeader(packetHeader,destAddr,srcAddr,destAddrLength);
  1940.  
  1941. mp->b_rptr += headerHideLength;    // "hide" the ethernet and protocol header(s) 
  1942.  
  1943.     // Append data to M_PROTO IND/TEST/XID block & pass it on to the client stream.
  1944. linkb(nmp, mp);
  1945. putnext(theStream->readQueue, nmp);        // pass the message up the stream
  1946. return;
  1947.  
  1948. }
  1949.  
  1950. //-----------------------------------------------------------------------------------------
  1951. //    Description:
  1952. //        This routine sends a test response packet that was created from the test request
  1953. //        that was received.  When auto handling is turned on during the bind, the dlpi
  1954. //        sends test responses when it receives a test request.
  1955. //
  1956. //        To send the response a control message block is built from the information in 
  1957. //        the received packet.  The Ethernet and protocol is then hidden in the original
  1958. //        request message block.  The two blocks are then linked together and passed to
  1959. //        the send unit data routine.
  1960. //
  1961. //    Input:
  1962. //        theStream - the stream sending the test reponse
  1963. //        mp - the message block containing the test request
  1964. //
  1965. //    Output:
  1966. //        NONE
  1967. //
  1968. //-----------------------------------------------------------------------------------------
  1969. void DoTestResponse(DLPIStream *theStream, mblk_t *mp)
  1970. {
  1971. T8022FullPacketHeader     *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
  1972. Boolean                 isSnap;
  1973. UInt32                     destAddrLength;
  1974. UInt32                     headerHideCount;
  1975. mblk_t                     *nmp;
  1976. dl_test_res_t             *responseStruct;
  1977. T8022AddressStruct         *destAddrTemplate;
  1978.  
  1979. /*zzz*/
  1980.     sprintf (debugStr, "DoTestResponse, theStream = %lx, mp = %lx", (long) theStream, (long) mp);
  1981.     DebugStr1 ((ConstStr255Param) c2pstr (debugStr));
  1982. /*zzz*/
  1983.     // since test is only valid for 802.2 we start we the basic values
  1984. destAddrLength = kEnetAndSAPAddressLength;
  1985. headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  1986. isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
  1987.  
  1988. if (isSnap) 
  1989.     {
  1990.     destAddrLength += k8022SNAPLength;
  1991.     headerHideCount += k8022SNAPLength;
  1992.     }
  1993.  
  1994.     // Allocate the dl_test_res_t message, and fill it in
  1995. if ((nmp = allocb(sizeof(dl_test_res_t) + destAddrLength, BPRI_HI)) == NULL) 
  1996.     {
  1997.     freemsg(mp);
  1998.     return;
  1999.     }
  2000.     
  2001. nmp->b_datap->db_type = M_PROTO;
  2002.  
  2003. responseStruct = (dl_test_res_t *)nmp->b_rptr;
  2004. responseStruct->dl_primitive = DL_TEST_RES;
  2005. responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
  2006. responseStruct->dl_dest_addr_length = destAddrLength;
  2007. responseStruct->dl_dest_addr_offset = sizeof(dl_test_res_t);
  2008.  
  2009. nmp->b_wptr += sizeof(dl_test_res_t);
  2010. destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
  2011.  
  2012. OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
  2013. destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
  2014.  
  2015. if (isSnap)
  2016.     OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
  2017.  
  2018. nmp->b_wptr += destAddrLength;
  2019. mp->b_rptr += headerHideCount;
  2020.  
  2021. linkb(nmp, mp);
  2022.  
  2023. /*zzz*/
  2024.     sprintf (debugStr, "DoTestResponse calling DoUnitData, theStream = %lx, nmp = %lx", (long) theStream, (long) nmp);
  2025.     DebugStr1 ((ConstStr255Param) c2pstr (debugStr));
  2026. /*zzz*/
  2027. DoUnitData(theStream, nmp);
  2028.  
  2029. }
  2030.  
  2031. //-----------------------------------------------------------------------------------------
  2032. //    Description:
  2033. //        This routine sends a xid response packet that was created from the xid request
  2034. //        that was received.  When auto handling is turned on during the bind, the dlpi
  2035. //        sends xid responses when it receives a xid request.
  2036. //
  2037. //        To send the response a control message block is built from the information in 
  2038. //        the received packet.  The Ethernet and protocol header is then hidden in the original
  2039. //        request message block.  The two blocks are then linked together and passed to
  2040. //        the send unit data routine.
  2041. //
  2042. //    Input:
  2043. //        theStream - the stream generating the xid response
  2044. //        mp - the message block containing the xid request message
  2045. //
  2046. //    Output:
  2047. //        NONE
  2048. //
  2049. //-----------------------------------------------------------------------------------------
  2050. void DoXidResponse(DLPIStream *theStream, mblk_t *mp)
  2051. {
  2052. T8022FullPacketHeader     *pktHdr = (T8022FullPacketHeader *)(mp->b_rptr);
  2053. Boolean                 isSnap;
  2054. UInt32                     destAddrLength;
  2055. UInt32                     headerHideCount;
  2056. mblk_t                     *nmp;
  2057. dl_xid_res_t             *responseStruct;
  2058. T8022AddressStruct         *destAddrTemplate;
  2059.  
  2060.     // since xid is only valid for 802.2 we start we the basic values
  2061. destAddrLength = kEnetAndSAPAddressLength;
  2062. headerHideCount = kEnetPacketHeaderLength + k8022BasicHeaderLength;
  2063. isSnap = (pktHdr->f8022Part.fSSAP == 0xAA);
  2064.  
  2065. if (isSnap) 
  2066.     {
  2067.     destAddrLength += k8022SNAPLength;
  2068.     headerHideCount += k8022SNAPLength;
  2069.     }
  2070.  
  2071.     // Allocate the dl_xid_res_t message, and fill it in
  2072. if ((nmp = allocb(sizeof(dl_xid_res_t) + destAddrLength, BPRI_HI)) == NULL) 
  2073.     {
  2074.     freemsg(mp);
  2075.     return;
  2076.     }
  2077.     
  2078. nmp->b_datap->db_type = M_PROTO;
  2079.  
  2080. responseStruct = (dl_xid_res_t *)nmp->b_rptr;
  2081. responseStruct->dl_primitive = DL_XID_RES;
  2082. responseStruct->dl_flag = (pktHdr->f8022Part.fCtrl & 0x10) ? DL_POLL_FINAL : 0;
  2083. responseStruct->dl_dest_addr_length = destAddrLength;
  2084. responseStruct->dl_dest_addr_offset = sizeof(dl_xid_res_t);
  2085.  
  2086. nmp->b_wptr += sizeof(dl_xid_res_t);
  2087. destAddrTemplate = (T8022AddressStruct *)nmp->b_wptr;
  2088.  
  2089. OTCopy48BitAddress(pktHdr->fEnetPart.fSourceAddr, destAddrTemplate->fHWAddr);
  2090. destAddrTemplate->fSAP = pktHdr->f8022Part.fSSAP;
  2091.  
  2092. if (isSnap)
  2093.     OTCopy8022SNAP(pktHdr->f8022Part.fSNAP,destAddrTemplate->fSNAP);
  2094.  
  2095. nmp->b_wptr += destAddrLength;
  2096. mp->b_rptr += headerHideCount;    // hide the ethernet and protocol headers
  2097.  
  2098. AddXIDInfoToPacketData(theStream,nmp, mp);        // send packet after adding xid info
  2099.  
  2100. }
  2101.  
  2102. //-----------------------------------------------------------------------------------------
  2103. //    Description:
  2104. //        This routine trys to add some xid information to the start of the packet
  2105. //        data.  Before we can modify the data we must make sure that the message
  2106. //        is not being used by anyone else.  If that is kTrue then we "backup" the
  2107. //        read pointer by 3 bytes and place the xid info at the beginning.
  2108. //
  2109. //        If the message is being used by someone else then an attempt to copy it is made.
  2110. //        If that goes okay then the original message is no longer needed so we free it.
  2111. //
  2112. //    Input:
  2113. //        theStream - the stream generating the xid response
  2114. //        mp - the message block containing the xid request message
  2115. //
  2116. //    Output:
  2117. //        NONE
  2118. //
  2119. //-----------------------------------------------------------------------------------------
  2120. void AddXIDInfoToPacketData(DLPIStream *theStream, mblk_t *headerMB, mblk_t *dataMB)
  2121. {
  2122. mblk_t    *theMB;
  2123.  
  2124. if (dataMB->b_datap->db_ref != 1)    // is anybody else using this message data
  2125.     {
  2126.     if ((theMB = copymsg(dataMB)) == NULL)    // try to make a copy of the message
  2127.         {
  2128.         freemsg(headerMB);    // could not make copy so lets just drop the packet
  2129.         freemsg(dataMB);
  2130.         return;
  2131.         }
  2132.     else
  2133.         {
  2134.         freemsg(dataMB);    // free the original
  2135.         dataMB = theMB;
  2136.         }
  2137.     }
  2138.  
  2139.  
  2140. dataMB->b_rptr -= 3;    // need to prepend xid response information before data
  2141.  
  2142.     // this xid response information can be found in the 802.2 spec., p. 52
  2143. dataMB->b_rptr[0] = 0x81;    // XID Format Identifier, IEEE Basic Format
  2144. dataMB->b_rptr[1] = 0x01;    // Type 1 LLC
  2145. dataMB->b_rptr[2] = 0x00;    // Receive window size, we now default to 0
  2146.  
  2147. linkb(headerMB, dataMB);
  2148. DoUnitData(theStream, headerMB);    
  2149.  
  2150. }
  2151.  
  2152.  
  2153.  
  2154.